package com.circle.interests.biz.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.circle.common.core.enums.Switch;
import com.circle.common.core.exception.RRException;
import com.circle.interests.biz.core.PrizeInventoryManageService;
import com.circle.interests.biz.core.PrizeWriteOffService;
import com.circle.interests.biz.core.protocol.InventoryConsumeCondition;
import com.circle.interests.biz.core.protocol.InventoryRollbackCondition;
import com.circle.interests.biz.core.protocol.PrizeWriteOffCondition;
import com.circle.interests.biz.core.protocol.PrizeWriteOffResultDto;
import com.circle.interests.biz.entity.PrizeInfo;
import com.circle.interests.biz.entity.PrizeWinRecord;
import com.circle.interests.biz.enums.PrizeStatusEnum;
import com.circle.interests.biz.mapper.PrizeWinRecordMapper;
import com.circle.interests.biz.service.IPrizeInfoService;
import com.circle.interests.biz.service.IPrizeWinRecordService;
import com.circle.prize.library.api.dto.PrizeReceiveResultDto;
import com.circle.prize.library.api.dto.PrizeWinResultDto;
import com.circle.prize.library.api.dto.UserPrizeDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * <p>
 * 奖品发放记录 服务实现类
 * </p>
 *
 * @author generator
 * @since 2021-12-05
 */
@Slf4j
@Service
@Transactional
public class PrizeWinRecordServiceImpl extends ServiceImpl<PrizeWinRecordMapper, PrizeWinRecord> implements IPrizeWinRecordService {

    @Resource
    private IPrizeInfoService prizeInfoService;
    @Resource
    private PrizeWriteOffService prizeWriteOffService;
    @Resource
    private PrizeInventoryManageService prizeInventoryManageService;

    @Override
    public PrizeWinResultDto winPrize(Integer sceneType, String sceneId, String openId, String prizeCode, Integer count, Integer price) {
        PrizeInfo prizeInfo = prizeInfoService.getByCode(prizeCode);
        // 扣减库存
        InventoryConsumeCondition condition = new InventoryConsumeCondition();
        condition.setSceneType(sceneType);
        condition.setSceneId(sceneId);
        condition.setPrizeId(prizeInfo.getId());
        condition.setPrizeCount(count);
        condition.setPrizePrice(price);
        boolean result = prizeInventoryManageService.consumeInventory(condition);
        if (!result) {
            throw new RRException("库存不足");
        }
        // 保存用户中奖信息
        PrizeWinRecord record = buildNewPrize(sceneType, sceneId, openId, prizeInfo, price);
        save(record);
        PrizeWinResultDto dto = new PrizeWinResultDto();
        dto.setRecordId(record.getId());
        dto.setOpenId(openId);
        dto.setPrizeCode(prizeCode);
        return dto;
    }

    @Override
    public PrizeReceiveResultDto receivePrize(Long recordId, String writeOffQrCode) {
        PrizeWinRecord record = getById(recordId);
        if (record == null) {
            throw new RRException("中奖记录不存在");
        }
        if (Switch.ON.getCode().equals(record.getRecycleFlag())) {
            throw new RRException("奖品已回收无法领取");
        }
        String writeOffCode = record.getWriteOffCode();
        if (PrizeStatusEnum.NOT_RECEIVE.getCode().equals(record.getStatus())) {
            writeOffCode = "YQ" + RandomUtil.randomStringUpper(8);
            PrizeWinRecord update = new PrizeWinRecord();
            update.setId(recordId);
            update.setWriteOffCode(writeOffCode);
            update.setWriteOffQrCode(writeOffQrCode);
            update.setReceiveTime(LocalDateTime.now());
            update.setStatus(PrizeStatusEnum.RECEIVED.getCode());
            updateById(update);
        } else if (StrUtil.isBlank(record.getWriteOffCode())) {
            log.error("奖品:{}状态:{}非法领取,{}", recordId, record.getStatus(), writeOffQrCode);
            throw new RRException("奖品状态不支持领取");
        }
        PrizeReceiveResultDto resultDto = new PrizeReceiveResultDto();
        resultDto.setRecordId(recordId);
        resultDto.setWriteOffCode(writeOffCode);
        return resultDto;
    }

    @Override
    public void expirePrize(Long recordId) {
        PrizeWinRecord record = getById(recordId);
        if (record == null) {
            throw new RRException("中奖记录不存在");
        }
        if (PrizeStatusEnum.NOT_RECEIVE.getCode().equals(record.getStatus())) {
            // 只修改状态值
            PrizeWinRecord update = new PrizeWinRecord();
            update.setId(recordId);
            update.setStatus(PrizeStatusEnum.EXPIRED_OF_NOT_RECEIVE.getCode());
            updateById(update);
        } else if (PrizeStatusEnum.RECEIVED.getCode().equals(record.getStatus())) {
            PrizeWinRecord update = new PrizeWinRecord();
            update.setId(recordId);
            update.setStatus(PrizeStatusEnum.EXPIRED_OF_RECEIVED.getCode());
            updateById(update);
        } else {
            throw new RRException("奖品状态" + PrizeStatusEnum.getByCode(record.getStatus()) + ",无法设置过期");
        }
    }

    @Override
    public void recyclePrize(Long recordId) {
        InventoryRollbackCondition condition = new InventoryRollbackCondition();
        condition.setRecordId(recordId);
        prizeInventoryManageService.recycleInventory(condition);
    }

    @Override
    public UserPrizeDto writeOff(Integer sceneType, String sceneId, String phoneNumber, String writeOffCode, String remark) {
        PrizeWinRecord record = getOne(Wrappers.lambdaQuery(PrizeWinRecord.class)
                .eq(PrizeWinRecord::getSceneType, sceneType).eq(PrizeWinRecord::getSceneId, sceneId).eq(PrizeWinRecord::getWriteOffCode, writeOffCode));
        if (record == null) {
            throw new RRException("核销码无效");
        }
        // 校验状态
        if (!Objects.equals(record.getStatus(), 2)) {
            throw new RRException("奖品无法核销");
        }
        // todo 待优化引入redis
        PrizeWinRecord update = new PrizeWinRecord();
        update.setStatus(5);
        boolean success = update(update, Wrappers.lambdaUpdate(PrizeWinRecord.class)
                .eq(PrizeWinRecord::getId, record.getId()).eq(PrizeWinRecord::getStatus, record.getStatus()));
        if (success) {
            PrizeWriteOffCondition condition = new PrizeWriteOffCondition();
            condition.setSceneId(sceneId);
            condition.setPrizeCategoryId(record.getPrizeCategoryId());
            condition.setPrizeId(record.getPrizeId());
            condition.setPrizeType(record.getPrizeType());
            condition.setOpenId(record.getOpenId());
            condition.setPhoneNumber(phoneNumber);
            condition.setPrizePrice(record.getPrizePrice());
            condition.setRemark(remark);
            PrizeWriteOffResultDto resultDto = prizeWriteOffService.writeOff(condition);
            Integer status = 6;
            if (Objects.equals(resultDto.getStatus(), 1)) {
                status = 5;
            } else if (Objects.equals(resultDto.getStatus(), 2)) {
                status = 6;
            } else if (Objects.equals(resultDto.getStatus(), 3)) {
                status = 7;
            }
            update = new PrizeWinRecord();
            update.setStatus(status);
            update.setWriteOffMessage(resultDto.getMessage());
            update(update, Wrappers.lambdaUpdate(PrizeWinRecord.class)
                    .eq(PrizeWinRecord::getId, record.getId()).eq(PrizeWinRecord::getStatus, record.getStatus()));
        }
        return null;
    }

    private PrizeWinRecord buildNewPrize(Integer sceneType, String sceneId, String openId, PrizeInfo prizeInfo, Integer price) {
        PrizeWinRecord entity = new PrizeWinRecord();
        entity.setAppId(prizeInfo.getAppId());
        entity.setSceneType(sceneType);
        entity.setSceneId(sceneId);
        entity.setPrizeCategoryId(prizeInfo.getCategoryId());
        entity.setPrizeId(prizeInfo.getId());
        entity.setPrizeName(prizeInfo.getName());
        entity.setPrizePrice(price != null ? price : prizeInfo.getPrice());
        entity.setPrizeOriginalPrice(prizeInfo.getOriginalPrice());
        entity.setPrizeType(prizeInfo.getType());
        entity.setPrizeSmallImg(prizeInfo.getSmallImg());
        entity.setOpenId(openId);
        entity.setStatus(PrizeStatusEnum.NOT_RECEIVE.getCode());
        entity.setRecycleFlag(Switch.OFF.getCode());
        entity.setWinTime(LocalDateTime.now());
        return entity;
    }

}
